package entity

import (
	"context"
	"time"

	"gitee.com/night-tc/gobige/common"
	"gitee.com/night-tc/gobige/global"
	"gitee.com/night-tc/gobige/logger"
	"gitee.com/night-tc/gobige/threads"
)

type IRun interface {
	/* 允许其他协程调用 */

	//进入对象销毁程序(不能重载)
	EnterDestroy()
	//是否已销毁
	IsDestroyed() bool
	//自运行协程的函数(不能重写)
	GoRun(ctx context.Context)

	/* 其他接口 */

	//设置协程管理器
	setThgo(thgo *threads.SubThreadGo)
	// 是否加载失败，如果失败，后面的逻辑就不继续下去了
	GetIsFailLoad() bool
	// 是否加载失败，如果失败，后面的逻辑就不继续下去了
	SetLoadFail()
}

type EntityRun struct {
	//后代对象 组件内使用
	realPtr IEntity
	//关闭独立协程的方法,如果会nil表示没有独立协程
	thgo *threads.SubThreadGo
	//是否加载失败，如果失败，后面的逻辑就不继续下去了
	isFailLoad bool
}

func (this *EntityRun) OnCreated(real IEntity) {
	this.realPtr = real
}

//----------------------------------------------------------------------------
/* 允许其他协程调用 */

// 进入对象销毁程序
func (this *EntityRun) EnterDestroy() {
	logger.Debugf(logger.LogKey_Entity, "EnterDestroy:%d", this.realPtr.GetEntityID())
	state := this.realPtr.GetEntityState()
	if state == Entity_State_Init ||
		state == Entity_State_Loop {
		//进入销毁状态
		this.realPtr.SetEntityState(Entity_State_Destroy)
		if this.thgo == nil {
			this.realPtr.Destroy()
		}
	}
}

// 是否已销毁
func (this *EntityRun) IsDestroyed() bool {
	return this.realPtr.GetEntityState() == Entity_State_Invalid
}

// 自运行协程的函数
func (this *EntityRun) GoRun(ctx context.Context) {
	logger.Debugf(logger.LogKey_Entity, "GoRun start:%d", this.realPtr.GetEntityID())
	defer logger.Debugf(logger.LogKey_Entity, "GoRun close:%d", this.realPtr.GetEntityID())
	// ticker := time.NewTicker(global.GetCfgInst().GetFrameDeltaTime())
	// defer ticker.Stop()
	this.realPtr.GetEntities().AddChan(this.realPtr.GetEntityID(), this.realPtr)
	defer this.realPtr.GetEntities().ReChan(this.realPtr.GetEntityID(), this.realPtr)
	for {
		select {
		case <-ctx.Done():
			if this.realPtr.GetEntityState() == Entity_State_Invalid {
				return
			} else {
				logger.Debugf(logger.LogKey_Entity, "GoRun Done ing:%d state:%d", this.realPtr.GetEntityID(), this.realPtr.GetEntityState())
				this.mainLoop()
				time.Sleep(1 * time.Second)
			}
			// e.realPtr.Destroy()
		case now := <-this.realPtr.GetTicker():
			this.realPtr.SetNowTime(now)
			this.mainLoop()
		case <-this.realPtr.GetCallChan():
			this.realPtr.DoMsg()
		}
	}
}

func (this *EntityRun) mainLoop() {
	defer func() {
		if global.GetCfgInst().GetRecover() {
			if err := recover(); err != nil {
				logger.Error("Entity MainLoop panic :", err)
				buf := common.StackTrace()
				common.OnRecover(err, buf, this.realPtr)
				this.realPtr.OnPanic(common.GetError(err))
			}
		}
	}()
	state := this.realPtr.GetEntityState()
	switch state {
	case Entity_State_Init:
		if err := this.realPtr.Init(); err != nil {
			this.realPtr.SetLoadFail()
			this.realPtr.GetEntities().CallDelay(func() {
				logger.Warnf("Reg SrvID failed DestroyEntity")
				_ = this.realPtr.GetEntities().DestroyEntity(this.realPtr.GetEntityID())
			})
		}
	case Entity_State_Loop:
		if this.realPtr.GetIsFailLoad() {
			this.realPtr.EnterDestroy()
			return
		}
		this.realPtr.Loop()
		this.realPtr.Looping()
		this.realPtr.Looped()
	case Entity_State_Destroy:
		this.realPtr.Destroy()
	case Entity_State_Prepare:
		this.realPtr.ReLoop()
	}
}

/* 允许其他协程调用 */
//----------------------------------------------------------------------------
/* 其他接口 */

// 设置协程结束函数
func (this *EntityRun) setThgo(destroyF *threads.SubThreadGo) {
	this.thgo = destroyF
}

// 是否加载失败，如果失败，后面的逻辑就不继续下去了
func (this *EntityRun) GetIsFailLoad() bool {
	return this.isFailLoad
}

// 是否加载失败，如果失败，后面的逻辑就不继续下去了
func (this *EntityRun) SetLoadFail() {
	this.isFailLoad = true
}

/* 其他接口 */
///////////////////////////////////////////////////////////////
